package logic

import (
	"context"
	"errors"
	"yuanxin-admin/internal/model"
	"yuanxin-admin/internal/repository"
	"yuanxin-admin/internal/service"
	"yuanxin-admin/internal/vo"

	"gitee.com/botaoshow/yuanxin/web/utils/strs"
	"github.com/gin-gonic/gin"
)

func NewSysMenuService() service.ISysMenuService {
	return &SysMenuServiceImpl{}
}

type SysMenuServiceImpl struct {
}

func (s SysMenuServiceImpl) Update(c *gin.Context, entity *model.SysMenu) (bool, error) {
	updates, err := repository.SysMenu.WithContext(c).
		Where(repository.SysMenu.MenuID.Eq(entity.MenuID)).
		Updates(entity)
	if err != nil {
		return false, err
	}
	return updates.RowsAffected > 0, nil
}

func (s SysMenuServiceImpl) Create(c *gin.Context, entity *model.SysMenu) (bool, error) {
	err := repository.SysMenu.WithContext(c).Create(entity)
	if err != nil {
		return false, err
	}
	return true, nil
}

func (s SysMenuServiceImpl) UpdateRoleMenus(c *gin.Context, roleId string, ids []int64) (bool, error) {
	_, err := repository.SysRoleMenu.WithContext(c).Where(repository.SysRoleMenu.RoleID.Eq(roleId)).Delete()
	if err != nil {
		return false, err
	}
	var list []*model.SysRoleMenu
	for _, id := range ids {
		list = append(list, &model.SysRoleMenu{
			ID:     strs.GetUUIDWithoutDashUpper(),
			RoleID: roleId,
			MenuID: id,
		})
	}
	err = repository.SysRoleMenu.WithContext(c).CreateInBatches(list, 100)
	if err != nil {
		return false, err
	}
	return true, nil
}

func (s SysMenuServiceImpl) SelectMenuList(context context.Context) ([]*vo.MenuVO, error) {
	list, err := repository.SysMenu.WithContext(context).Order(repository.SysMenu.OrderNum.Asc()).Find()
	if err != nil {
		return nil, err
	}
	//转化为 MenuVO
	menuVOList := make([]*vo.MenuVO, len(list))
	for i, menu := range list {
		if *menu.ParentID == 0 && *menu.MenuType == "M" {
			menuVO := &vo.MenuVO{
				MenuId:    menu.MenuID,
				MenuName:  menu.MenuName,
				ParentId:  menu.ParentID,
				OrderNum:  menu.OrderNum,
				Path:      menu.Path,
				Component: menu.Component,
				Query:     menu.Query,
				RouteName: menu.RouteName,
				IsFrame:   menu.IsFrame,
				IsCache:   menu.IsCache,
				MenuType:  menu.MenuType,
				Icon:      menu.Icon,
				Status:    menu.Status,
				Remark:    menu.Remark,
				Perms:     menu.Perms,
				Visible:   menu.Visible,
			}
			menuVOList[i] = menuVO
		}
	}
	//menuVOList 根据 orderNum 排序
	//sort.Slice(menuVOList, func(i, j int) bool {
	//if menuVOList[i].OrderNum == nil || menuVOList[j].OrderNum == nil {
	//	return false
	//}
	//return *menuVOList[i].OrderNum < *menuVOList[j].OrderNum
	//})
	for _, menuVO := range menuVOList {
		findChildrenMenu(menuVO, &list)
	}
	//删除null
	for i := 0; i < len(menuVOList); i++ {
		if menuVOList[i] == nil {
			menuVOList = append(menuVOList[:i], menuVOList[i+1:]...)
			i--
		}
	}
	return menuVOList, nil
}
func findChildrenMenu(menuVO *vo.MenuVO, list *[]*model.SysMenu) {
	if menuVO == nil {
		return
	}
	children := make([]*vo.MenuVO, 0)
	for _, menu := range *list {
		if menu.ParentID != nil && *menu.ParentID == menuVO.MenuId {
			menuVO := &vo.MenuVO{
				MenuId:    menu.MenuID,
				MenuName:  menu.MenuName,
				ParentId:  menu.ParentID,
				OrderNum:  menu.OrderNum,
				Path:      menu.Path,
				Component: menu.Component,
				Query:     menu.Query,
				RouteName: menu.RouteName,
				IsFrame:   menu.IsFrame,
				IsCache:   menu.IsCache,
				MenuType:  menu.MenuType,
				Icon:      menu.Icon,
				Status:    menu.Status,
				Remark:    menu.Remark,
				Perms:     menu.Perms,
				Visible:   menu.Visible,
			}
			if menuVO != nil {
				children = append(children, menuVO)
			}
		}
	}
	menuVO.Children = children
	for _, menuVO := range children {
		findChildrenMenu(menuVO, list)
	}
}

func (s SysMenuServiceImpl) RoleMenu(context context.Context) ([]*vo.PageMenuVO, error) {
	list, err := s.SelectMenuList(context)
	if err != nil {
		return nil, err
	}
	return convert(list), nil

}
func convert(menuVOS []*vo.MenuVO) []*vo.PageMenuVO {
	if menuVOS == nil {
		return nil
	}
	//PageMenuVO
	pageMenuVOS := make([]*vo.PageMenuVO, len(menuVOS))
	for _, menuVO := range menuVOS {
		if menuVO == nil {
			continue
		}
		pageMenuVO := &vo.PageMenuVO{
			Name:      menuVO.MenuName,
			Path:      menuVO.Path,
			Component: menuVO.Component,
			Meta: &vo.PageMenuMetaVO{
				Title:     menuVO.MenuName,
				Icon:      menuVO.Icon,
				KeepAlive: *menuVO.IsCache == 0,
				Query:     menuVO.Query,
				IsFrame:   *menuVO.IsFrame == 0,
				IsCache:   *menuVO.IsCache == 0,
				MenuType:  menuVO.MenuType,
				Perms:     menuVO.Perms,
				Visible:   *menuVO.Visible == "0",
				Status:    menuVO.Status,
				Remark:    menuVO.Remark,
			},
		}
		pageMenuVO.Children = convert(menuVO.Children)
		pageMenuVOS = append(pageMenuVOS, pageMenuVO)

	}

	//pageMenuVOS 移出 nil
	for i := 0; i < len(pageMenuVOS); i++ {
		if pageMenuVOS[i] == nil {
			pageMenuVOS = append(pageMenuVOS[:i], pageMenuVOS[i+1:]...)
			i--
		}
	}
	return pageMenuVOS
}
func (s SysMenuServiceImpl) RoleMenuByRoles(context context.Context, roles []string) ([]*vo.PageMenuVO, error) {
	// 获取角色ID
	var roleIds []string
	err := repository.SysRole.WithContext(context).
		Select(repository.SysRole.ID).Where(repository.SysRole.RoleCode.In(roles...)).Scan(&roleIds)
	if err != nil {
		return nil, err
	}

	// 获取角色对应的菜单ID
	var sysRoleMenuIds []int64
	err = repository.SysRoleMenu.WithContext(context).
		Select(repository.SysRoleMenu.MenuID).
		Distinct(repository.SysRoleMenu.MenuID).
		Where(repository.SysRoleMenu.RoleID.In(roleIds...)).
		Scan(&sysRoleMenuIds)
	if err != nil {
		return nil, err
	}

	// 获取所有菜单
	menuVOS, err := s.SelectMenuList(context)
	if err != nil {
		return nil, err
	}

	// 过滤有权限的菜单
	var res []*vo.MenuVO
	for _, menuVO := range menuVOS {
		// 检查当前菜单或其子菜单是否有权限
		if hasPermission(menuVO, sysRoleMenuIds) {
			// 过滤子菜单
			filteredChildren := filterChildrenByPermission(menuVO.Children, sysRoleMenuIds)
			if len(filteredChildren) > 0 || contains(sysRoleMenuIds, menuVO.MenuId) {
				newMenuVO := *menuVO
				newMenuVO.Children = filteredChildren
				if &newMenuVO != nil {
					res = append(res, &newMenuVO)
				}
			}
		}
	}

	return convert(res), nil
}

func (s SysMenuServiceImpl) SafeDeleteById(context context.Context, id int64) (bool, error) {
	count, err := repository.SysMenu.WithContext(context).
		Where(repository.SysMenu.ParentID.Eq(id)).
		Count()
	if err != nil {
		return false, err
	}
	if count > 0 {
		return false, errors.New("存在子菜单，请先删除子菜单")
	}
	resultInfo, err := repository.SysMenu.WithContext(context).Delete(&model.SysMenu{
		MenuID: id,
	})
	return resultInfo.RowsAffected > 0, err
}

// 检查菜单或其子菜单是否有权限
func hasPermission(menuVO *vo.MenuVO, roleMenuIds []int64) bool {
	if menuVO == nil {
		return false
	}
	if contains(roleMenuIds, menuVO.MenuId) {
		return true
	}
	for _, child := range menuVO.Children {
		if hasPermission(child, roleMenuIds) {
			return true
		}
	}
	return false
}

// 过滤有权限的子菜单
func filterChildrenByPermission(children []*vo.MenuVO, roleMenuIds []int64) []*vo.MenuVO {
	var result []*vo.MenuVO
	for _, child := range children {
		if contains(roleMenuIds, child.MenuId) {
			filteredChildren := filterChildrenByPermission(child.Children, roleMenuIds)
			newChild := *child
			newChild.Children = filteredChildren
			result = append(result, &newChild)
		}
	}
	return result
}

// 检查ID是否在列表中
func contains(ids []int64, id int64) bool {
	for _, v := range ids {
		if v == id {
			return true
		}
	}
	return false
}
